/************************************************
 * Author       :   XXY
 * Blog         :   https://www.cnblogs.com/jzyl
 * Gitee        :   https://gitee.com/xiaobaichong
 * Email        :   1047185209@QQ.com
 * FileName     :   CoroutineUtility.cs
 * CreateData   :   2023/5/24 10:27:20
 * UnityVersion :   2021.3.20f1c1
 * Description  :   协程实用工具类
************************************************/

using AOT;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

namespace Main
{
    /// <summary>
    /// 协程实用工具类
    /// </summary>
    public static class CoroutineUtility
    {
        private static List<ExecuteAfterTime> executeFrames = new List<ExecuteAfterTime>(); // 延迟帧后执行
        private static List<ExecuteAfterTime> executeSeconds = new List<ExecuteAfterTime>();// 延迟秒后执行
        private static Mono _mono;
        private static Mono mono
        {
            get
            {
                if (_mono == null)
                {
                    GameObject go = new GameObject("CoroutineUtility");
                    go.hideFlags = HideFlags.HideInHierarchy;
                    GameObject.DontDestroyOnLoad(go);
                    _mono = go.AddComponent<Mono>();
                    executeFrames.Clear();
                    executeSeconds.Clear();
                    _mono.StartCoroutine(FrameHandler());
                    _mono.StartCoroutine(SecondHandler());
                }
                return _mono;
            }
        }
        #region 延迟 执行
        #region 延迟 处理器 心脏
        private static IEnumerator FrameHandler()
        {
            while (true)
            {
                yield return null;
                for (int i = 0; i < executeFrames.Count;)
                {
                    executeFrames[i].time--;
                    if (executeFrames[i].time < 0)
                    {
                        executeFrames[i].func?.Invoke();
                        executeFrames.RemoveAt(i);
                    }
                    else
                    {
                        i++;
                    }
                }
            }
        }
        private static IEnumerator SecondHandler()
        {
            while (true)
            {
                yield return new WaitForSecondsRealtime(0.1f);
                for (int i = 0; i < executeSeconds.Count;)
                {
                    executeSeconds[i].time -= 0.1f;
                    if (executeSeconds[i].time < 0)
                    {
                        executeSeconds[i].func?.Invoke();
                        executeSeconds.RemoveAt(i);
                    }
                    else
                    {
                        i++;
                    }
                }
            }
        }
        #endregion

        /// <summary>
        /// 执行一个方法在某帧之后
        /// </summary>
        /// <param name="func">要被执行的方法</param>
        /// <param name="FrameCount">等待多少帧</param>
        public static void ActionForFrame(Action func, int FrameCount = 1)
        {
            _ = mono;
            if (FrameCount > 0)
            {
                ExecuteAfterTime execute = new ExecuteAfterTime(FrameCount, func);
                executeFrames.Add(execute);
            }
        }
        /// <summary>
        /// 等待多少秒后执行方法
        /// </summary>
        /// <param name="func">要执行的方法</param>
        /// <param name="SecondCount">延迟多少时间</param>
        public static void ActionForSecond(Action func, float SecondCount = 1)
        {
            _ = mono;
            if (SecondCount > 0)
            {
                ExecuteAfterTime execute = new ExecuteAfterTime(SecondCount, func);
                executeSeconds.Add(execute);
            }
        }
        #endregion

        #region 下载处理器
        #region 加载 处理器 免费劳动力
        private static IEnumerator ProgressBar(UnityWebRequest www, Action<float> Progress)
        {
            while (!www.isDone)
            {
                yield return null;
                Progress?.Invoke(www.downloadProgress);
            }
        }
        private static IEnumerator DownLoadAB(string url, Action<AssetBundle> Completed, Action<float> Progress)
        {
            using (UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(url))
            {
                Coroutine coroutine = mono.StartCoroutine(ProgressBar(www, Progress));
                yield return www.SendWebRequest();
                if (www.result == UnityWebRequest.Result.Success)
                {
                    AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(www);
                    Completed?.Invoke(bundle);
                }
                else
                {
                    LogUtillity.Error(www.error);
                    Completed?.Invoke(null);
                }
                mono.StopCoroutine(coroutine);
            }
        }
        private static IEnumerator DownLoadAudio(string url, AudioType type, Action<AudioClip> Completed, Action<float> Progress)
        {
            using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(url, type))
            {
                Coroutine coroutine = mono.StartCoroutine(ProgressBar(www, Progress));
                yield return www.SendWebRequest();

                if (www.result == UnityWebRequest.Result.Success)
                {
                    AudioClip clip = DownloadHandlerAudioClip.GetContent(www);
                    Completed?.Invoke(clip);
                }
                else
                {
                    LogUtillity.Error(www.error);
                    Completed?.Invoke(null);
                }
                mono.StopCoroutine(coroutine);
            }
        }
        private static IEnumerator DownLoadTexture(string url, Action<Texture> Completed, Action<float> Progress)
        {
            using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(url))
            {
                Coroutine coroutine = mono.StartCoroutine(ProgressBar(www, Progress));
                yield return www.SendWebRequest();

                if (www.result == UnityWebRequest.Result.Success)
                {
                    var tex = DownloadHandlerTexture.GetContent(www);
                    Completed?.Invoke(tex);
                }
                else
                {
                    LogUtillity.Error(www.error);
                    Completed?.Invoke(null);
                }

                mono.StopCoroutine(coroutine);
            }
        }
        private static IEnumerator DownLoadText(string url, Action<string> Completed, Action<float> Progress)
        {
            using (UnityWebRequest www = UnityWebRequest.Get(url))
            {
                Coroutine coroutine = mono.StartCoroutine(ProgressBar(www, Progress));
                yield return www.SendWebRequest();

                if (www.result == UnityWebRequest.Result.Success)
                {
                    var str = www.downloadHandler.text;
                    Completed?.Invoke(str);
                }
                else
                {
                    LogUtillity.Error(www.error);
                    Completed?.Invoke("");
                }

                mono.StopCoroutine(coroutine);
            }
        }
        private static IEnumerator DownLoadData(string url, Action<byte[]> Completed, Action<float> Progress)
        {
            using (UnityWebRequest www = UnityWebRequest.Get(url))
            {
                Coroutine coroutine = mono.StartCoroutine(ProgressBar(www, Progress));
                yield return www.SendWebRequest();

                if (www.result == UnityWebRequest.Result.Success)
                {
                    var str = www.downloadHandler.data;
                    Completed?.Invoke(str);
                }
                else
                {
                    LogUtillity.Error(www.error);
                    Completed?.Invoke(null);
                }
                mono.StopCoroutine(coroutine);
            }
        }

        #endregion

        /// <summary>
        /// 加载AB包
        /// </summary>
        /// <param name="url">链接</param>
        /// <param name="Completed">完成回调</param>
        /// <param name="Progress">加载进度</param>
        public static void LoadAB(string url, Action<AssetBundle> Completed, Action<float> Progress = null)
        {
            mono.StartCoroutine(DownLoadAB(url, Completed, Progress));
        }
        /// <summary>
        /// 加载音频
        /// </summary>
        /// <param name="url">链接</param>
        /// <param name="type">音频类型</param>
        /// <param name="Completed">完成回调</param>
        /// <param name="Progress">加载进度</param>
        public static void LoadAudio(string url, AudioType type, Action<AudioClip> Completed, Action<float> Progress = null)
        {
            mono.StartCoroutine(DownLoadAudio(url, type, Completed, Progress));
        }
        /// <summary>
        /// 加载音频（仅支持 JPG 和 PNG 格式）
        /// </summary>
        /// <param name="url">链接</param>
        /// <param name="Completed">完成回调</param>
        /// <param name="Progress">加载进度</param>
        public static void LoadTexture(string url, Action<Texture> Completed, Action<float> Progress = null)
        {
            mono.StartCoroutine(DownLoadTexture(url, Completed, Progress));
        }
        /// <summary>
        /// 获取文本内容
        /// </summary>
        /// <param name="url">链接</param>
        /// <param name="Completed">完成回调</param>
        /// <param name="Progress">进度回调</param>
        public static void LoadText(string url, Action<string> Completed, Action<float> Progress = null)
        {
            mono.StartCoroutine(DownLoadText(url, Completed, Progress));
        }
        /// <summary>
        /// 获取下载字节
        /// </summary>
        /// <param name="url">链接</param>
        /// <param name="Completed">完成回调</param>
        /// <param name="Progress">进度回调</param>
        public static void LoadData(string url, Action<byte[]> Completed, Action<float> Progress = null)
        {
            mono.StartCoroutine(DownLoadData(url, Completed, Progress));
        }
        #endregion
    }
    /// <summary>
    /// 延迟执行类
    /// </summary>
    public class ExecuteAfterTime
    {
        // 时间
        public float time;
        // 要要执行的方法
        public Action func;
        public ExecuteAfterTime(float time, Action action)
        {
            this.time = time;
            func = action;
        }
    }
}
